package il.ac.tau.dbcourse.logic;

import il.ac.tau.dbcourse.db.ConnectionFactory;
import il.ac.tau.dbcourse.db.DBException;
import il.ac.tau.dbcourse.db.PersistenceManager;
import il.ac.tau.dbcourse.db.UserTrack;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.Connection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.cmc.music.common.ID3ReadException;
import org.cmc.music.metadata.MusicMetadata;
import org.cmc.music.metadata.MusicMetadataSet;
import org.cmc.music.myid3.MyID3;

public class MP3Scanner {
	private MP3Scanner(PrintStream ps, Connection conn) throws DBException {
		out = ps;
		this.conn = conn;

	}

	public static class MatchCallable implements Callable<Boolean> {

		private UserTrack userTrack;
		private Connection conn;

		public MatchCallable(UserTrack userTrack, Connection conn) {
			this.userTrack = userTrack;
			this.conn = conn;
		}

		@Override
		public Boolean call() throws Exception {
			try {
				return new Boolean(MixAndMatch.matchTrack(userTrack, conn));
			} catch (DBException e) {
				return Boolean.FALSE;
			}
		}

	}

	// need this counter in case we want to limit the number of songs to scan
	private int songsCounter = 0; 
	private PrintStream out;
	private Connection conn;
	private ExecutorService pool = Executors.newFixedThreadPool(3);

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void scan(File dir, PrintStream ps) throws Exception {
		Connection conn = ConnectionFactory.getConnection();
		PersistenceManager.truncateUserTrack(conn);
		MP3Scanner mp3Scanner = new MP3Scanner(ps,conn);
		mp3Scanner.scanDirForMp3Files(dir);
		mp3Scanner.join();

	}

	private void scanDirForMp3Files(File diskRoot) throws Exception {
		File[] files_list = diskRoot.listFiles();

		// if empty directory
		if (files_list == null)
			return;

		for (int i = 0; i < files_list.length; i++) {
			if (files_list[i].isFile()) {
				if (isMp3File(files_list[i]))
					id3Parser(files_list[i]);
			} else {
				out.println("Scanning " + files_list[i] + "...");
				scanDirForMp3Files(files_list[i]);
			}

			// same limit again, i dont want to use "goto"
			if (songsCounter > 100000)
				return;
		}
	}

	private static boolean isMp3File(File file) {
		String filename = file.getName();
		if (filename.endsWith("mp3"))
			return true;
		else
			return false;
	}

	private void join() {
		try{
			pool.shutdown();
			pool.awaitTermination(5, TimeUnit.SECONDS);

		} catch (Exception e){
			
		}
	}

	private void id3Parser(File src) throws ID3ReadException, IOException {
		MusicMetadataSet src_set = new MyID3().read(src); // read metadata

		if (src_set == null) // perhaps no metadata
		{
			return;
		}

		// Debug.debug("src_set", src_set); // dump all info.

		MusicMetadata metadata = (MusicMetadata) src_set.getSimplified();
		String song_title = metadata.getSongTitle();
		if (song_title == null) {
			System.out.println("*** no id3 tags for: " + src.getName()
					+ "   ***");
			return;
		}

		String artist = metadata.getArtist();
		String album = metadata.getAlbum();
		Number year = metadata.getYear();

		UserTrack userTrack = new UserTrack(src.getAbsolutePath());
		userTrack.setTitle(song_title);
		userTrack.setAlbumName(album);
		userTrack.setArtistName(artist);
		PersistenceManager.save(conn, userTrack);

		Callable<Boolean> callable = new MatchCallable(userTrack, conn);
		pool.submit(callable);

		out.println("%%%%%");
		out.println("songs_counter " + songsCounter + "\n");
		out.println("song_title = " + song_title + "\n");
		out.println("artist = " + artist + "\n");
		out.println("album = " + album + "\n");
		out.println("year = " + year + "\n\n");

		songsCounter++;

	}
}
